///////////////////////////////////////////////////////////////////////////
// Copyright 2009 Arabic Game Developer Network, All rights reserved
// www.agd-online.com - info@agdn-online.com
//
// File: eventmanager.h
// Description:
//
///////////////////////////////////////////////////////////////////////////

// This file is part of kvalleyX.
// 
// kvalleyX is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// kvalleyX is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with kvalleyX.  If not, see <http://www.gnu.org/licenses/>.

#ifndef _EVENTMANAGER_H
#define _EVENTMANAGER_H

#include "input.h"
#include <string>
#include <queue>
#include <boost/signal.hpp>
#include <boost/bind.hpp>

namespace CoreLib
{
	class Event
	{
		public:
			enum EventType
			{
				QUIT_EVENT,
				KEY_EVENT,
				RENDER_EVENT,
				UPDATE_EVENT,
				STATE_EVENT,
			};
		
		private:
			EventType type;

		public:
			Event(const EventType type) : type(type) {}
			
			Event& operator=(const Event& right)
			{
				type = right.type;
				return *this;
			}
			
			bool operator<(const Event& right) const
			{
				return (type < right.type);
			}

			bool operator==(const Event& right) const
			{
				return (type == right.type);
			}

			inline const EventType getType() const
			{
				return type;
			}
	};


	///TODO: removet eventtypes and use specialized subclasses instead.
	class StateEvent : public Event
	{
		public:
			enum EventType
			{
				STATE_EXIT,
				STATE_TRANSIT,
				STATE_RENDER
			};
			
		private:
			EventType eventType;
			std::string eventName;
		
		public:
			inline EventType getEventType() const
			{
				return eventType;
			}

			inline std::string getName() const
			{
				return eventName;
			}
			StateEvent(StateEvent::EventType type,const std::string name) :
			Event(Event::STATE_EVENT), eventType(type), eventName(name) {}
	};

	class EventManager
	{
		public:
			///TODO: add other signals for the rest
			///FIXME: utilize boos::signals2 for a threadsafe variant.
			typedef boost::signal<void (void)> sig_update_t;
			typedef boost::signal<void (void)> sig_quit_t;
			typedef boost::signals::connection connection_t;
			
		private:
			sig_update_t sig_update;
			sig_quit_t sig_quit;
			std::queue<Event> events;

		private:
			inline void updateEvents()
			{
				static const Event quitEvent(Event::QUIT_EVENT);
				if(isQuit())
					fireEvent(quitEvent);
			}

		protected:
			// 		virtual EventType pollEvents() = 0;
// 			virtual void getKeyEvent(InputManager const
// 			*inputManagerPtr) = 0;
			virtual bool isQuit() = 0;

 		public:
			virtual void init() = 0;

			void update()
			{
				dispatchEvents();
			}
			
			void fireEvent(const Event &event)
			{
				events.push(event);
			}

			///TODO: add similar for the other signals.
			connection_t connect_update(const sig_update_t::slot_type slot)
			{
				return sig_update.connect(slot);
			}

			connection_t connect_quit(const sig_quit_t::slot_type slot)
			{
				return sig_quit.connect(slot);
			}

		private:
			void dispatchEvents()
			{
				// FIXME: update events should not be called from here.
				updateEvents();
				while(!events.empty())
				{
					Event &event = events.front();
					events.pop();
					switch(event.getType())
					{
						case Event::QUIT_EVENT:
							sig_quit();
							break;
						case Event::UPDATE_EVENT:
							sig_update();
							break;
						case Event::STATE_EVENT:
							///TODO: signal state
							break;
						case Event::KEY_EVENT:
							///TODO: signal key
							break;
						case Event::RENDER_EVENT:
							///TODO: signal render
							break;
					}
				}
			}
	};
}

#endif
